/**
  ******************************************************************************
  * @file    USART/USART_DMA for STM32F407
  * @author  cowpea
  * @version V1.1
  * @date    2013.10.9
  * @brief   RX receive 10 bits data and generate a DMA interrupt
  ******************************************************************************
  * @attention
  *
  * @ TX -> PD8
  *	@ RX -> PD9
  * @  
	* 
  *
  * 
  * 
  * 
  * 
  * 
  * v1.1 brief:
	* @config dma in my_printf function, to transfer more data once
  * 
  *
  * 
  *
  * 
  * 
  * 
  * 
  * 
  *
  ******************************************************************************
  */

/* Includes ------------------------------------------------------------------*/
#include "usart.h"
#include "stdlib.h"

/* Private typedef -----------------------------------------------------------*/
//typedef enum {FAILED = 0, PASSED = !FAILED} TestStatus;
/* Private define ------------------------------------------------------------*/
  /* Misc definition **********************************************************/
//#define	USART_TX_BUFFSIZE	10
#define USART_RX_BUFFSIZE	10

#ifndef NULL
#define NULL 0 
#endif


/* Definition for USARTx resources ********************************************/
  #define USARTx                           USART3
  #define USARTx_CLK                       RCC_APB1Periph_USART3
  #define USARTx_CLK_INIT                  RCC_APB1PeriphClockCmd
  #define USARTx_IRQn                      USART3_IRQn
  #define USARTx_IRQHandler                USART3_IRQHandler

  #define USARTx_TX_PIN                    GPIO_Pin_8                
  #define USARTx_TX_GPIO_PORT              GPIOD                       
  #define USARTx_TX_GPIO_CLK               RCC_AHB1Periph_GPIOD
  #define USARTx_TX_SOURCE                 GPIO_PinSource8
  #define USARTx_TX_AF                     GPIO_AF_USART3

  #define USARTx_RX_PIN                    GPIO_Pin_9                
  #define USARTx_RX_GPIO_PORT              GPIOD                    
  #define USARTx_RX_GPIO_CLK               RCC_AHB1Periph_GPIOD
  #define USARTx_RX_SOURCE                 GPIO_PinSource9
  #define USARTx_RX_AF                     GPIO_AF_USART3

/* Definition for DMAx resources **********************************************/

  #define USARTx_DMA                       DMA1
  #define USARTx_DMAx_CLK                  RCC_AHB1Periph_DMA1
     
  #define USARTx_TX_DMA_CHANNEL            DMA_Channel_4
  #define USARTx_TX_DMA_STREAM             DMA1_Stream3
  #define USARTx_TX_DMA_FLAG_FEIF          DMA_FLAG_FEIF3
  #define USARTx_TX_DMA_FLAG_DMEIF         DMA_FLAG_DMEIF3
  #define USARTx_TX_DMA_FLAG_TEIF          DMA_FLAG_TEIF3
  #define USARTx_TX_DMA_FLAG_HTIF          DMA_FLAG_HTIF3
  #define USARTx_TX_DMA_FLAG_TCIF          DMA_FLAG_TCIF3
              
  #define USARTx_RX_DMA_CHANNEL            DMA_Channel_4
  #define USARTx_RX_DMA_STREAM             DMA1_Stream1
  #define USARTx_RX_DMA_FLAG_FEIF          DMA_FLAG_FEIF1
  #define USARTx_RX_DMA_FLAG_DMEIF         DMA_FLAG_DMEIF1
  #define USARTx_RX_DMA_FLAG_TEIF          DMA_FLAG_TEIF1
  #define USARTx_RX_DMA_FLAG_HTIF          DMA_FLAG_HTIF1
  #define USARTx_RX_DMA_FLAG_TCIF          DMA_FLAG_TCIF1

  #define USARTx_DMA_TX_IRQn               DMA1_Stream3_IRQn
  #define USARTx_DMA_RX_IRQn               DMA1_Stream1_IRQn
  #define USARTx_DMA_TX_IRQHandler         DMA1_Stream3_IRQHandler
  #define USARTx_DMA_RX_IRQHandler         DMA1_Stream1_IRQHandler
	#define DMA_TX_TCIF											 DMA_IT_TCIF3
	#define DMA_RX_TCIF											 DMA_IT_TCIF1


/* Private variables ---------------------------------------------------------*/
uint8_t aTxBuffer[USART_RX_BUFFSIZE] = "hello \t\n";// Example: Communication between two USART using DMA";
uint8_t aRxBuffer[USART_RX_BUFFSIZE] = {0};
//__IO uint32_t TimeOut = 0x0; 
__IO u8 TXBusy = 0;//
//__IO unsigned char *P = NULL;
DMA_InitTypeDef  DMA_InitStructure;

/* Private function prototypes -----------------------------------------------*/
void DMA_data_change(void);

/* Private function prototypes -----------------------------------------------*/

/**
	* @printf function
	*/
PUTCHAR_PROTOTYPE
{
  /* Place your implementation of fputc here */
 
	/* Loop until the end of last transmission */
	while( TXBusy ) {};
	while ( USART_GetFlagStatus( USART3 , USART_FLAG_TC ) == RESET ) {};
  /* e.g. write a character to the USART */
  USART_SendData(USART3, (uint8_t) ch);
		
  return ch;
}

/**
	* @config USART with DMA interrupt
	*/
void USART_Config(void)
{
  USART_InitTypeDef USART_InitStructure;
  GPIO_InitTypeDef GPIO_InitStructure;
	NVIC_InitTypeDef NVIC_InitStructure;


/* Peripheral Clock Enable -------------------------------------------------*/
/* Enable GPIO clock */
  RCC_AHB1PeriphClockCmd(USARTx_TX_GPIO_CLK | USARTx_RX_GPIO_CLK, ENABLE);
  
/* Enable USART clock */
  USARTx_CLK_INIT(USARTx_CLK, ENABLE);
  
/* Enable the DMA clock */
  RCC_AHB1PeriphClockCmd(USARTx_DMAx_CLK, ENABLE);
  
/* USARTx GPIO configuration -----------------------------------------------*/ 
/* Connect USART pins to AF7 */
  GPIO_PinAFConfig(USARTx_TX_GPIO_PORT, USARTx_TX_SOURCE, USARTx_TX_AF);
  GPIO_PinAFConfig(USARTx_RX_GPIO_PORT, USARTx_RX_SOURCE, USARTx_RX_AF);
  
  /* Configure USART Tx and Rx as alternate function push-pull */
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
  
  GPIO_InitStructure.GPIO_Pin = USARTx_TX_PIN;
  GPIO_Init(USARTx_TX_GPIO_PORT, &GPIO_InitStructure);
  
  GPIO_InitStructure.GPIO_Pin = USARTx_RX_PIN;
  GPIO_Init(USARTx_RX_GPIO_PORT, &GPIO_InitStructure);
	
	
	/* Enable the DMA Stream IRQ Channel */
  NVIC_InitStructure.NVIC_IRQChannel = USARTx_DMA_TX_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure); 
	
	NVIC_InitStructure.NVIC_IRQChannel = USARTx_DMA_RX_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
	NVIC_Init(&NVIC_InitStructure);
 
  /* USARTx configuration ----------------------------------------------------*/
  /* Enable the USART OverSampling by 8 */
  USART_OverSampling8Cmd(USARTx, ENABLE); 
  
  /* USARTx configured as follow:
        - BaudRate = 128000 baud
		   - Maximum BaudRate that can be achieved when using the Oversampling by 8
		     is: (USART APB Clock / 8) 
			 Example: 
			    - (USART3 APB1 Clock / 8) = (42 MHz / 8) = 5250000 baud
			    - (USART1 APB2 Clock / 8) = (84 MHz / 8) = 10500000 baud
		   - Maximum BaudRate that can be achieved when using the Oversampling by 16
		     is: (USART APB Clock / 16) 
			 Example: (USART3 APB1 Clock / 16) = (42 MHz / 16) = 2625000 baud
			 Example: (USART1 APB2 Clock / 16) = (84 MHz / 16) = 5250000 baud
        - Word Length = 8 Bits
        - one Stop Bit
        - No parity
        - Hardware flow control disabled (RTS and CTS signals)
        - Receive and transmit enabled
  */ 
  USART_InitStructure.USART_BaudRate = 128000;
  USART_InitStructure.USART_WordLength = USART_WordLength_8b;
  USART_InitStructure.USART_StopBits = USART_StopBits_1;
  /* When using Parity the word length must be configured to 9 bits */
  USART_InitStructure.USART_Parity = USART_Parity_No;
  USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
  USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
  USART_Init(USARTx, &USART_InitStructure);

  /* Configure DMA controller to manage USART TX and RX DMA request ----------*/ 
   
  /* Configure DMA Initialization Structure */
  DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable ;
  DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_1QuarterFull ;
  DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single ;
  DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
  DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
  DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
  DMA_InitStructure.DMA_PeripheralBaseAddr =(uint32_t) (&( USARTx -> DR)) ;
  DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
  DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
  DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
  DMA_InitStructure.DMA_Priority = DMA_Priority_High;
	
	/* Configure RX DMA */
	DMA_InitStructure.DMA_BufferSize = USART_RX_BUFFSIZE ;
  DMA_InitStructure.DMA_Channel = USARTx_RX_DMA_CHANNEL ;
  DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory ;
  DMA_InitStructure.DMA_Memory0BaseAddr =(uint32_t)aRxBuffer ; 
  DMA_Init(USARTx_RX_DMA_STREAM,&DMA_InitStructure);
	
  /* Configure TX DMA */
	//	DMA_InitStructure.DMA_BufferSize = USART_TX_BUFFSIZE ;
  DMA_InitStructure.DMA_Channel = USARTx_TX_DMA_CHANNEL ;
  DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral ;
  DMA_InitStructure.DMA_Memory0BaseAddr =(uint32_t)aTxBuffer ;
  DMA_Init(USARTx_TX_DMA_STREAM,&DMA_InitStructure);

  
	/* Enable DMA Stream Transfer Complete interrupt */
  DMA_ITConfig(USARTx_TX_DMA_STREAM, DMA_IT_TC, ENABLE);
	DMA_ITConfig(USARTx_RX_DMA_STREAM, DMA_IT_TC, ENABLE);
	
  /* Enable USART */
  USART_Cmd(USARTx, ENABLE);
	/* Enable USART RX DMA */
	DMA_Cmd(USARTx_RX_DMA_STREAM,ENABLE);
	USART_DMACmd(USARTx, USART_DMAReq_Rx, ENABLE);
	/* Enable USART TX DMA */
//	DMA_Cmd(USARTx_TX_DMA_STREAM,ENABLE);
	USART_DMACmd(USARTx, USART_DMAReq_Tx, ENABLE);
}

/**
  * @brief  handles DMA Stream interrupt request.
  * @param  None
  * @retval None
  */
void USARTx_DMA_TX_IRQHandler(void)
{

  /* Test on DMA Stream Transfer Complete interrupt */
  if(DMA_GetITStatus(USARTx_TX_DMA_STREAM, DMA_TX_TCIF))
  {
    /* Clear DMA Stream Transfer Complete interrupt pending bit */
    DMA_ClearITPendingBit(USARTx_TX_DMA_STREAM, DMA_TX_TCIF); 
		TXBusy = 0;//release TX resources
	}
}

/**
  * @brief  handles DMA Stream interrupt request.
  * @param  None
  * @retval None
  */
void USARTx_DMA_RX_IRQHandler(void)
{
	char i=0;
	if(DMA_GetITStatus(USARTx_RX_DMA_STREAM, DMA_RX_TCIF))
  {
    /* Clear DMA Stream Transfer Complete interrupt pending bit */
    DMA_ClearITPendingBit(USARTx_RX_DMA_STREAM, DMA_RX_TCIF);  
		

		
    while(i<USART_RX_BUFFSIZE)
			aTxBuffer[ i++ ]=aRxBuffer[i];
		My_Print(aTxBuffer);	//transfer data to TX port
		
    //DMA_Cmd(USARTx_TX_DMA_STREAM,ENABLE);
		DMA_Cmd(USARTx_RX_DMA_STREAM,ENABLE);
		
  }
}


/**
  * @brief  transfer char arry to USART DMA
  * @param  pointer to an arry
  * @retval weather the trasfer suceed
	* @ the function can use as following to replace printf

	sprintf(c,"%10d\r\n",nTime);//c must be an unsigned char arry defined before,
	My_Print(c);

  */
unsigned char My_Print(unsigned char *arry)
{
	char i = 0;
	while( *(arry + i) != '\0')
		i++;
	DMA_InitStructure.DMA_BufferSize = i ;
  DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t) arry ; 
  DMA_Init(USARTx_TX_DMA_STREAM,&DMA_InitStructure);
	
	while( TXBusy ) {};
	DMA_Cmd(USARTx_TX_DMA_STREAM,ENABLE);
	TXBusy = 1;
	return 1;
	
}



